#pragma once
#include <iostream>
#include <string>
#include <cstring>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#define PATH "." //定义管道文件所在的路径
#define FILENAME "fifo" // 定义管道文件的名称

//////////////////////////////////////////////////
//    命名管道类 -- 负责创建和销毁管道文件        //
//////////////////////////////////////////////////

class NamedFifo {
public:
    NamedFifo(const std::string& path, const std::string& name)
    :_path(path)
    ,_name(name)
    {
        umask(0);
        _fifoname = _path + "/" + _name;

        // 创建管道文件
        int n = mkfifo(_fifoname.c_str(), 0666);
        if(n < 0) {
            std::cerr << "Error: Failed to create FIFO file!" << std::endl;
        }
        else {
            std::cout << "Success: FIFO file created at!" <<std::endl;
        }
    }
    // 析构 -- 删除管道文件
    ~NamedFifo() {
        int n = unlink(_fifoname.c_str());
        if(n == 0) {
            std::cout << "Success: FIFO file removed ( " << _fifoname << " )" << std::endl;
        }
        else {
            std::cerr << "Error: Failed to removed FIFO file ( " << _fifoname << " )" << std::endl;
        }
    }
private:
    std::string _path;      // 管道文件所在路径
    std::string _name;     // 管道文件名称
    std::string _fifoname; // 管道文件绝对路径
};

//////////////////////////////////////////////////
//         文件操作类 -- 负责读写操作            //
//////////////////////////////////////////////////

class FileOper {
public:
    FileOper(const std::string& path, const std::string& name)
    :_path(path)
    ,_name(name)
    {
        _fifoname = _path + "/" + _name;
    }

    // 打开管道文件 -- 读模式
    void OpenForRead() {
        _fd = open(_fifoname.c_str(), O_RDONLY);
        if(_fd < 0) {
            std::cerr << "Error: Failed to open FIFO for reading ( " << _fifoname << " )" << std::endl;
            return;
        }
        std::cout << "Success: FIFO opened for reading ( " << _fifoname << " )" << std::endl;
    }

    // 打开管道文件 -- 写模式
    void OpenForWrite() {
        _fd = open(_fifoname.c_str(), O_WRONLY);
        if(_fd < 0) {
            std::cerr << "Error: Failed to open FIFO for writing ( " << _fifoname << " )" << std::endl;
            return;
        }
        std::cout << "Success: FIFO opened for writing ( " << _fifoname << " )" << std::endl;
    }

    // 从管道文件中读取文件
    void Read() {
        // 正常接收
        while(1) {
            char buffer[1024];
            int number = read(_fd, buffer, sizeof(buffer) - 1);
            if(number > 0) {
                buffer[number] = 0;
                std::cout << "服务端接收到 --- 客户端说: " << buffer << std::endl; 
            }
            else if(number == 0){
                sleep(1);
                std::cout << "Client quit !!! me too !!!" << std::endl;
                break;
            }
            else {
                std::cerr << "read faile" << std::endl;
                return;
            }
        }
    }
    
    // 从管道文件中写数据
    void Write() {
        // 构造发送的信息
        std::string message;
        int cnt = 1;
        pid_t id = getpid();
        while(1) {
            std::cout << "Client: Please Enter# ";
            std::getline(std::cin, message);
            message = "\"" + message + "\"" + (" --- message number is " + std::to_string(cnt++) + ", [ " + std::to_string(id) + " ]");
            write(_fd, message.c_str(), message.size());
        }
    }

    // 关闭管道文件
    void Close() {
        if(_fd > 0) {
            close(_fd);
            std::cout << "FIFO closed!" << std::endl;
        }
    }
private:
    std::string _path;      // 管道文件所在路径
    std::string _name;     // 管道文件名称
    std::string _fifoname; // 管道文件绝对路径
    int _fd;               // 文件描述符
};